Processing math: 100%

POI2014 Salad Bar

POI2014 Salad Bar

题目大意:

有一个长度为n的字符串,每一位只会是pj。你需要取出一个子串S(从左到右或从右到左一个一个取出),使得不管是从左到右还是从右往左取,都保证每时每刻已取出的p的个数不小于j的个数。你需要最大化|S|

题解:

首先很容易想到把每一个p看做1,把每一个j看做1,之后通过前缀和sum)来判断是否满足条件。

如果一个子串[L,R]是合法的,那么必然满足以下条件:

k[L+1,R],sumisumksumj

反之,只要满足了上述条件,这个子串一定合法。

于是,我们不难想到,枚举一个每一个L,对于每一个L,向后找R

对于一个L, 找L右边第一个sumi小的下标k

那么显然,k以及k右边的点,都无法做i的右端点。

因而只能在区间[L+1,k1]找右端点。

因为要使sumLsumxsumR,显然区间中sum最大的哪一个即为右端点。(若最大有多个,取最右边的那个。)

这个可以用反证法:

假设我们不以最大的为右端点。

那么有两种情况:

  1. 最大的点在你取的点的左边,那么这样最大的点在[L+1R]之间,但是sum值却比R 大,显然是不合法的。
  2. 最大的点在你取的点的右边。那么我们取最大的点一定可以满足,并且还比当前点更优,因而还不如取最大的那个。

综上所述,我们得到了一种复杂度为O(nlogn)的算法。

首先可以O(n) 预处理出每一个左端点的右端点存在的可能区间。

之后对于每一个左端点,我们在区间查询最大值即可。(这个可以用线段树等数据结构来写,单次查询为O(logn))。


但实际上还有一种O(n)的写法:

不妨把问题具象化:

把前缀和看做是高度,由于每一次更改的值绝对值为1 ,因而一个个sum连成了一幅连续的折线图。

我们把向上凸起的称为山峰,向下凹的称为山谷

那么对于每一个点,我们要找的实际上是,往右延伸时,在不出现比当前点高度矮的山谷的前提下,最高的山峰的位置。

这个可以用dp来写。

  1. stri=p ,那么我们有 peaki={peaki+1(sumpeaki+1>sumpeaknxti)peaknxti(sumpeaki+1sumpeaknxti)
  2. stri=j ,那么我们有peak i=i

其中nxti表示,下一个出现的与当前点高度相同的点的位置。

我们可以O(n)预处理出nxt数组,又可以O(n)实现dp值的转移。

综上题目即可解。

Code:

这里只给出O(n)的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1000002;
char str[N];
int n,mi,sum[N];
int nxt[N];//下一个出现的与当前点高度相同的点的位置
int vis[N<<1];
int peak[N];
int main(){
scanf("%d %s",&n,str+1);
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+(str[i]=='p'?1:-1);
memset(vis,-1,sizeof(vis));
for(int i=n;i>=0;i--){
sum[i]=sum[i]+N;
nxt[i]=vis[sum[i]];
vis[sum[i]]=i;
}
int cpeak,ans=0;
peak[n]=cpeak=n;
for(int i=n;i>=1;i--){
if(str[i]=='p'){
if(~nxt[i-1]&&sum[peak[nxt[i-1]]]>=sum[cpeak])peak[i-1]=cpeak=peak[nxt[i-1]];
else peak[i-1]=cpeak;
ans=max(ans,cpeak-i+1);
}
else peak[i-1]=cpeak=i-1;
}
printf("%d\n",ans);
return 0;
}
/**************************************************************
User: YummyJay
Language: C++
Result: 正确
Time:24 ms
Memory:22204 kb
****************************************************************/
分享到 评论